//
// File:	Sound.cpp
// Author:	Thomas TISSOT-DUPONT
// Login:	<thomas.tissotdupont@free.fr>
//
// Created:	28/04/2010 at 02:45:26
// Purpose:	
//
#include "Base.hpp"
#include "Sound.hpp"
#include "ResourceManager.hpp"
#include "ResourceManagerTypes.hpp"
#include "Parser.hpp"
#include "Trace.hpp"

//------------------------------------------------------------------
// Constructor / Destructor
//------------------------------------------------------------------
Sound::Sound()
	:	m_bRemoved(false),
		m_flMutedVolume(0.0f),
		m_bIsMuted(false),
		m_vfPosition(0, 0),
		m_bSpatializable(true)
{
}

Sound::~Sound()
{
}

//------------------------------------------------------------------
// Load From File
//------------------------------------------------------------------
bool Sound::LoadFromFile(const std::string &filename)
{

	//Mendatory Keys
	std::list<std::string> mendatoryKeys;
	mendatoryKeys.push_back("sound");

	//Parse file
	Parser parser;
	if (!parser.ParseFromFile(filename))
		return false;

	//Get root element
	const Parser::Element *pRootElement = parser.GetRootElement().FindChild("sound");
	if (pRootElement == NULL)
		return false;

	//Check sound mendatory keys
	if (pRootElement->HasKeys(mendatoryKeys) == false)
		return false;

	//Load the sound buffer
	sf::SoundBuffer *pSoundBuffer = SoundResourceManager::GetInstance().Find(pRootElement->GetValueForKey("sound"));
	if (pSoundBuffer == NULL)
		return false;
	sf::Sound::SetBuffer(*pSoundBuffer);

	//Read the (optional) properties
	SetVolume(			pRootElement->GetValueForKey("volume",			Variant(100.0f)));
	SetLoop(			pRootElement->GetValueForKey("loop",			Variant(false)));
	SetSpatializable(	pRootElement->GetValueForKey("spatialization",	Variant(true)));
	return true;
}

//------------------------------------------------------------------
// Play / Stop / Pause
//------------------------------------------------------------------
void Sound::Play()
{
	sf::Sound::SetPosition(0, 0, 0);
	sf::Sound::SetAttenuation(0.0f);
	sf::Sound::SetRelativeToListener(true);
	sf::Sound::Play();
	emit OnPlayed(this);
}

void Sound::Stop()
{
	sf::Sound::Stop();
	emit OnStopped(this);
}

void Sound::Pause()
{
	sf::Sound::Pause();
	emit OnPaused(this);
}

//------------------------------------------------------------------
// Mute / UnMute
//------------------------------------------------------------------
void Sound::Mute()
{
	if (!m_bIsMuted)
	{
		m_flMutedVolume = GetVolume();
		SetVolume(0.0f);
		m_bIsMuted = !m_bIsMuted;
		emit OnMuted(this);
	}
}

void Sound::UnMute()
{
	if (m_bIsMuted)
	{
		SetVolume(m_flMutedVolume);
		m_bIsMuted = !m_bIsMuted;
		emit OnUnmuted(this);
	}
}

//------------------------------------------------------------------
// Update
//------------------------------------------------------------------
void Sound::Update()
{
	//HACK: quick and dirty "not playing" event dispatching
	if (sf::Sound::GetStatus() != sf::Sound::Playing)
	{
		switch (sf::Sound::GetStatus())
		{
		case sf::Sound::Paused:
			break;
		default:
			Stop();
			break;
		}
	}
	emit OnUpdated(this);
}

//------------------------------------------------------------------
// Remove
//------------------------------------------------------------------
void Sound::Remove()
{
	m_bRemoved = true;
	GlobalVariables::EventManager::Get().DisconnectTarget(this);
	GlobalVariables::EventManager::Get().DisconnectCaller(this);
}

bool Sound::IsRemoved() const
{
	return m_bRemoved;
}

//------------------------------------------------------------------
// Loop
//------------------------------------------------------------------
void Sound::SetLoop(bool bLoop)
{
	sf::Sound::SetLoop(bLoop);
}

//------------------------------------------------------------------
// Volume
//------------------------------------------------------------------
void Sound::SetVolume(float flVolume)
{
	sf::Sound::SetVolume(flVolume);
}

float Sound::GetVolume() const
{
	return sf::Sound::GetVolume();
}

//------------------------------------------------------------------
// Position
//------------------------------------------------------------------
void Sound::SetX(float flX)
{
	m_vfPosition.x = flX;
}

void Sound::SetY(float flY)
{
	m_vfPosition.y = flY;
}

float Sound::GetX() const
{
	return m_vfPosition.x;
}

float Sound::GetY() const
{
	return m_vfPosition.y;
}

//------------------------------------------------------------------
// Spatialization
//------------------------------------------------------------------
void Sound::SetSpatializable(bool bSpatializable)
{
	m_bSpatializable = bSpatializable;
}

bool Sound::IsSpatializable() const
{
	return m_bSpatializable;
}
